Skip to content

Rich-text fixes (Mobile, Enter, Range errors, alignment etc.)#1802

Merged
myieye merged 10 commits into
developfrom
heavy-rich-text-bug-fixing
Jul 11, 2025
Merged

Rich-text fixes (Mobile, Enter, Range errors, alignment etc.)#1802
myieye merged 10 commits into
developfrom
heavy-rich-text-bug-fixing

Conversation

@myieye

@myieye myieye commented Jul 3, 2025

Copy link
Copy Markdown
Collaborator

Resolves #1699
Resolves #1792

And fixes numerous other issues 😆.

With this PR, I basically can't find any more differences between our rich-text input and standard inputs on Chrome, Firefox or Chrome on my phone.

Fixes:

  • Empty, readonly rich-text field labels weren't aligned with the input, because the input had no "baseline" for it to align with
  • Tabbing into readonly rich-text didn't select the text
  • The "Enter" key on mobile now knows it's a "Next" key and behaves as such. It preserves the previous know caret location of the field it jumps into
  • Range errors were happening, because prose-mirror seemed to be doing stuff with Enter keydown events and they weren't cancellable enough in the keymap, so I handle and cancel them high up
  • Rich-text lines now only break/wrap if they actually have real line breaks. Otherwise they scroll horizontally on overflow like normal inputs.
  • I think perhaps the correct usage of whitespace: 'pre', inline: true (as values given to prose-mirror) fixed our backspace/delete issues. That all seems fine now.
  • The alignment of text within the fields and the heights of the fields are identical.

@coderabbitai

coderabbitai Bot commented Jul 3, 2025

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This update enhances the rich text editor’s schema, focus, and selection handling, especially for keyboard and mobile interactions. It introduces new utilities for tabbable elements, adds comprehensive tests, adjusts Storybook and test scripts, and provides new Storybook stories for editor fields. Minor changes affect component initialization and styling.

Changes

File(s) Change Summary
frontend/viewer/package.json, frontend/viewer/vitest.config.ts Added "test:browser" script; updated Storybook script; renamed browser test project.
frontend/viewer/src/lib/components/lcm-rich-text-editor/lcm-rich-text-editor.svelte Refined ProseMirror schema, focus/selection logic, Enter key handling, and styling; added new exports and functions.
frontend/viewer/src/lib/utils/tabbable.ts, frontend/viewer/src/lib/utils/tabbable.test.ts Added findNextTabbable, improved findFirstTabbable, and introduced comprehensive Vitest test suite.
frontend/viewer/src/lib/components/ui/input/input-shell.svelte Simplified focus ring class logic for styling.
frontend/viewer/src/project/NewEntryButton.svelte Changed id initialization to use props instead of generating a new UUID.
frontend/viewer/src/stories/editor/entity-primitives/entry-editor-primitive.stories.svelte Replaced dynamic UUID with a fixed string for the entry id.
frontend/viewer/src/stories/editor/fields/1_overview.stories.svelte Added new Storybook stories showcasing various editor field states and alignments.

Assessment against linked issues

Objective Addressed Explanation
Fix cursor jump: First character ends up as last in empty rich-string field (#1699)
Backspace issue after clicking at end of rich-string field (#1699)
Delete key deletes whole span after tab/reverse-tab (#1699)
Tabbing in should select all text like normal input, except when returning via reverse-tab (#1699)
Pressing Enter in rich-text fields should be ignored to prevent RangeError and visual glitches (#1792)

Assessment against linked issues: Out-of-scope changes

Code Change (file_path) Explanation
Added new Storybook stories for editor fields (frontend/viewer/src/stories/editor/fields/1_overview.stories.svelte) This addition provides UI demos and is not directly related to the rich-string field bug fixes.
Changed id initialization in NewEntryButton (frontend/viewer/src/project/NewEntryButton.svelte) This change is unrelated to the rich-text field or Enter key issues.
Replaced dynamic UUID with fixed string in entry-editor-primitive.stories.svelte This is a test data adjustment, unrelated to the linked issues.
Added/modified Vitest scripts and config (frontend/viewer/package.json, vitest.config.ts) These changes pertain to test infrastructure, not to the specific bug fixes in the linked issues.

Possibly related PRs

  • #1755: Also modifies lcm-rich-text-editor.svelte for span underlining logic; both PRs update the same component but for different features.
  • #1747: Adds and configures Storybook and Vitest scripts, directly overlapping with the test and Storybook script updates here.
  • #1568: Introduces the initial lcm-rich-text-editor component, which this PR further extends and refines.

Suggested labels

💻 FW Lite

Suggested reviewers

  • hahn-kev

Poem

In fields of text where rabbits type,
The Enter key now takes a hike!
Cursors leap no more astray,
Backspace works the proper way.
With focus rings and stories new,
This bunny brings fresh code to you!
🐇✨


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions Bot added the 💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related label Jul 3, 2025
@github-actions

github-actions Bot commented Jul 3, 2025

Copy link
Copy Markdown
Contributor

UI unit Tests

  1 files  ± 0   38 suites  +3   11s ⏱️ -1s
 76 tests +19   76 ✅ +19  0 💤 ±0  0 ❌ ±0 
107 runs  +21  107 ✅ +21  0 💤 ±0  0 ❌ ±0 

Results for commit 6d0307d. ± Comparison against base commit 995fe62.

♻️ This comment has been updated with latest results.

@argos-ci

argos-ci Bot commented Jul 3, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) 👍 Changes approved 4 changed Jul 9, 2025, 3:47 AM

@github-actions

github-actions Bot commented Jul 3, 2025

Copy link
Copy Markdown
Contributor

C# Unit Tests

126 tests  ±0   126 ✅ ±0   12s ⏱️ ±0s
 20 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 6d0307d. ± Comparison against base commit 995fe62.

♻️ This comment has been updated with latest results.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
frontend/viewer/src/project/NewEntryButton.svelte (1)

25-33: Add missing id prop declaration and ensure backward compatibility.

The id prop is used on line 36 but not declared in the props interface. This could cause TypeScript errors and runtime failures if the prop is not provided.

Apply this diff to add the missing prop declaration:

  const {
    onclick,
    active,
    shortForm = false,
+   id,
  }: {
    onclick: () => void;
    shortForm?: boolean;
    active?: boolean;
+   id: string;
  } = $props();
🧹 Nitpick comments (3)
frontend/viewer/src/lib/utils/tabbable.ts (1)

22-50: Consider adding infinite loop protection to findNextTabbable.

The function logic is sound, but the while loop could potentially run indefinitely if the DOM structure is malformed or circular. Consider adding a maximum iteration limit as a safeguard.

 export function findNextTabbable(
   current: HTMLElement | SVGElement | null | undefined
 ): HTMLElement | SVGElement | undefined {
   if (!current?.parentElement) {
     return current ?? undefined;
   }

   if (!isTabbable(current, {displayCheck})) {
     throw new Error('Current element is not tabbable, so can\'t find relative tabbable element');
   }

   let container = current.parentElement;
   let tabbables = tabbable(container, {displayCheck});
+  let iterations = 0;
+  const MAX_ITERATIONS = 100; // Reasonable limit for DOM depth
   while (tabbables.length === 0 // should never happen, but whatever
     || tabbables.at(-1) === current // we're still last, so haven't found a "next" yet
   ) {
+    if (++iterations > MAX_ITERATIONS) {
+      console.warn('Max iterations reached in findNextTabbable, possible DOM issue');
+      return tabbables[0] ?? current;
+    }
     if (!container.parentElement) return tabbables[0]; // loop back to first
     container = container.parentElement;
     tabbables = tabbable(container, {displayCheck});
   }

   const currentIndex = tabbables.indexOf(current);
   if (currentIndex === -1) {
     throw new Error('Current tabbable element should always be in an ancestor\'s list of tabbables');
   }

   return tabbables[currentIndex + 1] ??
     tabbables[0]; // loop back to first
 }
frontend/viewer/src/lib/components/lcm-rich-text-editor/lcm-rich-text-editor.svelte (2)

132-135: The 100ms timeout for pointer detection may be fragile.

The hardcoded 100ms delay could lead to race conditions on slower devices or under heavy load. Consider using a more reliable method to distinguish pointer from keyboard interactions.

Instead of a timeout, consider tracking the pointer state more explicitly:

-        pointerdown() {
-          pointerDown = true;
-          setTimeout(() => pointerDown = false, 100); // yes, apparently we need a decently high timeout value
-        },
+        pointerdown() {
+          pointerDown = true;
+        },
+        pointerup() {
+          pointerDown = false;
+        },

210-218: Document the root cause of the Enter key range errors.

The comment mentions that Enter causes range errors on both mobile and desktop. It would be helpful to understand and document the specific ProseMirror issue causing these errors to ensure this workaround remains appropriate in future updates.

Would you like me to help investigate the specific range errors caused by Enter key handling in ProseMirror?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10d8832 and 0041f96.

📒 Files selected for processing (9)
  • frontend/viewer/package.json (1 hunks)
  • frontend/viewer/src/lib/components/lcm-rich-text-editor/lcm-rich-text-editor.svelte (16 hunks)
  • frontend/viewer/src/lib/components/ui/input/input-shell.svelte (1 hunks)
  • frontend/viewer/src/lib/utils/tabbable.test.ts (1 hunks)
  • frontend/viewer/src/lib/utils/tabbable.ts (2 hunks)
  • frontend/viewer/src/project/NewEntryButton.svelte (1 hunks)
  • frontend/viewer/src/stories/editor/entity-primitives/entry-editor-primitive.stories.svelte (1 hunks)
  • frontend/viewer/src/stories/editor/fields/1_overview.stories.svelte (1 hunks)
  • frontend/viewer/vitest.config.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: myieye
PR: sillsdev/languageforge-lexbox#1758
File: frontend/viewer/src/project/browse/BrowseView.svelte:78-85
Timestamp: 2025-06-18T09:23:29.799Z
Learning: For keyboard accessibility in TabsList components, myieye implements Enter key handlers on the TabsList rather than relying on change events that would interfere with arrow key navigation.
frontend/viewer/src/project/NewEntryButton.svelte (1)
Learnt from: hahn-kev
PR: sillsdev/languageforge-lexbox#1710
File: frontend/viewer/src/project/browse/BrowseView.svelte:17-19
Timestamp: 2025-05-27T06:18:33.852Z
Learning: The NewEntryButton component in frontend/viewer/src/project/NewEntryButton.svelte already internally checks features.write permission and conditionally renders based on write access, so external disabled props are not needed.
frontend/viewer/src/lib/components/ui/input/input-shell.svelte (3)
Learnt from: hahn-kev
PR: sillsdev/languageforge-lexbox#1757
File: frontend/viewer/src/lib/components/field-editors/multi-select.svelte:130-136
Timestamp: 2025-06-18T05:13:00.591Z
Learning: In frontend/viewer/src/lib/components/field-editors/multi-select.svelte, the computeCommandScore function from 'bits-ui' handles empty filter strings appropriately and does not hide all options when the filter is empty, contrary to initial analysis assumptions.
Learnt from: myieye
PR: sillsdev/languageforge-lexbox#1758
File: frontend/viewer/src/project/browse/BrowseView.svelte:78-85
Timestamp: 2025-06-18T09:23:29.799Z
Learning: In Svelte Tabs components, using `on:change` event handler would cause popups to close when users navigate with arrow keys, which creates poor UX. The user myieye prefers the current activation mode over `activationMode="manual"` and considers arrow key popup closing to be "too eager" behavior.
Learnt from: hahn-kev
PR: sillsdev/languageforge-lexbox#1710
File: frontend/viewer/src/project/browse/BrowseView.svelte:17-19
Timestamp: 2025-05-27T06:18:33.852Z
Learning: The NewEntryButton component in frontend/viewer/src/project/NewEntryButton.svelte already internally checks features.write permission and conditionally renders based on write access, so external disabled props are not needed.
frontend/viewer/src/stories/editor/fields/1_overview.stories.svelte (3)
Learnt from: myieye
PR: sillsdev/languageforge-lexbox#1536
File: backend/FwLite/LcmCrdt/Changes/CreateSenseChange.cs:43-44
Timestamp: 2025-03-17T13:16:24.769Z
Learning: In the SIL FieldWorks Language Explorer (FLEx) system, only certain fields support rich text formatting (embedded styles): Definition, Example sentences, Translations, Notes, and Literal meaning fields. Other fields like Gloss, Lexeme form, and Citation form are plain text only. The codebase reflects this distinction by using RichMultiString for rich-text capable fields and MultiString for plain text fields.
Learnt from: myieye
PR: sillsdev/languageforge-lexbox#1536
File: backend/FwLite/LcmCrdt/Changes/CreateSenseChange.cs:43-44
Timestamp: 2025-03-17T13:16:24.769Z
Learning: In the SIL FieldWorks Language Explorer (FLEx) system, only certain fields support rich text formatting (embedded styles): Definition, Example sentence, Translation, Note, and Literal meaning fields. Other fields like Gloss, Lexeme form, and Citation form are plain text only. The codebase reflects this by using RichMultiString for rich-text capable fields and MultiString for plain text fields.
Learnt from: hahn-kev
PR: sillsdev/languageforge-lexbox#1757
File: frontend/viewer/src/lib/components/field-editors/multi-select.svelte:130-136
Timestamp: 2025-06-18T05:13:00.591Z
Learning: In frontend/viewer/src/lib/components/field-editors/multi-select.svelte, the computeCommandScore function from 'bits-ui' handles empty filter strings appropriately and does not hide all options when the filter is empty, contrary to initial analysis assumptions.
frontend/viewer/src/lib/components/lcm-rich-text-editor/lcm-rich-text-editor.svelte (5)
Learnt from: hahn-kev
PR: sillsdev/languageforge-lexbox#1757
File: frontend/viewer/src/lib/components/field-editors/multi-select.svelte:130-136
Timestamp: 2025-06-18T05:13:00.591Z
Learning: In frontend/viewer/src/lib/components/field-editors/multi-select.svelte, the computeCommandScore function from 'bits-ui' handles empty filter strings appropriately and does not hide all options when the filter is empty, contrary to initial analysis assumptions.
Learnt from: myieye
PR: sillsdev/languageforge-lexbox#1758
File: frontend/viewer/src/project/browse/BrowseView.svelte:78-85
Timestamp: 2025-06-18T09:23:29.799Z
Learning: For keyboard accessibility in TabsList components, myieye implements Enter key handlers on the TabsList rather than relying on change events that would interfere with arrow key navigation.
Learnt from: myieye
PR: sillsdev/languageforge-lexbox#1758
File: frontend/viewer/src/project/browse/BrowseView.svelte:78-85
Timestamp: 2025-06-18T09:23:29.799Z
Learning: In Svelte Tabs components, using `on:change` event handler would cause popups to close when users navigate with arrow keys, which creates poor UX. The user myieye prefers the current activation mode over `activationMode="manual"` and considers arrow key popup closing to be "too eager" behavior.
Learnt from: hahn-kev
PR: sillsdev/languageforge-lexbox#1612
File: frontend/viewer/src/lib/entry-editor/DeleteDialog.svelte:39-52
Timestamp: 2025-04-18T10:33:51.961Z
Learning: Svelte 5 uses standard HTML attribute syntax for event handlers (e.g., `onclick={handler}`) instead of the Svelte-specific directive syntax (e.g., `on:click={handler}`) used in previous versions.
Learnt from: hahn-kev
PR: sillsdev/languageforge-lexbox#1612
File: frontend/viewer/src/lib/entry-editor/DeleteDialog.svelte:39-52
Timestamp: 2025-04-18T10:33:51.961Z
Learning: Svelte 5 uses standard HTML attribute syntax for event handlers (e.g., `onclick={handler}`) instead of the Svelte-specific directive syntax (e.g., `on:click={handler}`) used in previous versions.
🧬 Code Graph Analysis (1)
frontend/viewer/src/lib/utils/tabbable.test.ts (1)
frontend/viewer/src/lib/utils/tabbable.ts (2)
  • findFirstTabbable (6-20)
  • findNextTabbable (22-50)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: Build UI / publish-ui
  • GitHub Check: Build API / publish-api
  • GitHub Check: check-and-lint
  • GitHub Check: frontend
  • GitHub Check: Build FW Lite and run tests
  • GitHub Check: frontend-component-unit-tests
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (15)
frontend/viewer/src/stories/editor/entity-primitives/entry-editor-primitive.stories.svelte (1)

11-11: LGTM! Using a hardcoded UUID improves test reliability.

Using a fixed UUID in test stories is a good practice as it ensures reproducible test results and makes debugging easier. The hardcoded UUID follows the correct v4 format.

frontend/viewer/src/lib/components/ui/input/input-shell.svelte (1)

11-11: Good simplification of focus ring styling.

The refactoring to apply ring-ring, outline-none, and ring-offset-2 unconditionally while keeping only ring-2 conditional on focus-visible improves clarity and maintainability.

frontend/viewer/src/lib/utils/tabbable.ts (1)

1-4: Good environment-aware configuration for tabbable checks.

The displayCheck configuration appropriately handles different environments, using 'none' for tests (jsdom) where display checks aren't reliable, and 'full' for production.

frontend/viewer/src/lib/components/lcm-rich-text-editor/lcm-rich-text-editor.svelte (3)

36-41: Verify the unusual inline: true configuration for the doc node.

Setting inline: true on the doc node is atypical in ProseMirror schemas, as doc nodes are usually block-level containers. While this may be intentional for your specific rich-text input behavior, please confirm this doesn't cause unexpected side effects with ProseMirror's internal assumptions.


341-356: Good improvement to input consistency with InputShell wrapper.

Using InputShell as the wrapper component with tabindex={-1} elegantly solves the focus ring styling while keeping the editor as the actual tab target. This aligns well with the PR's goal of making rich-text inputs behave consistently with standard inputs.


312-339: Excellent CSS fixes for rich-text behavior and alignment.

The changes effectively address the PR objectives:

  • white-space: pre ensures lines only break on actual line breaks, matching standard input behavior
  • The zero-width space ::before content cleverly maintains baseline alignment when empty
  • Horizontal scrolling with hidden scrollbar provides a clean appearance

These improvements create the consistent behavior between rich-text and standard inputs.

frontend/viewer/vitest.config.ts (1)

37-37: LGTM! Simplified project naming.

The rename from "browser (non storybook)" to "browser" improves clarity and aligns with the new test:browser npm script.

frontend/viewer/package.json (2)

33-33: Good addition of browser-specific test command.

The test:browser script provides a convenient way to run browser-specific tests in isolation, complementing the existing test commands.


39-39: Note: Storybook will be accessible on all network interfaces.

Adding --host 0.0.0.0 makes Storybook accessible from any network interface, not just localhost. This is useful for testing on different devices but be aware of the security implications when running on untrusted networks.

frontend/viewer/src/stories/editor/fields/1_overview.stories.svelte (3)

1-16: Well-structured Storybook setup with comprehensive component imports.

The imports and setup properly include all necessary field editor components, demo data, and writing systems. The organization supports thorough testing of the rich-text editor improvements mentioned in the PR objectives.


18-249: Excellent comprehensive demo covering all field types and states.

This story effectively showcases all editor field components in various states (standard, readonly, empty, readonly/empty), which is perfect for testing the rich-text fixes mentioned in the PR objectives:

  • Alignment issues between readonly and standard fields
  • Multi-line text handling with newlines
  • Mixed writing system spans in rich text fields
  • Empty state handling

The grid layout organization makes it easy to visually compare different field types and their behaviors.


251-260: Perfect alignment testing story for the rich-text fixes.

This story directly addresses the alignment issues mentioned in the PR objectives by placing standard and rich inputs side-by-side in a flex container. This will help verify that the baseline alignment fixes for empty, readonly rich-text field labels are working correctly.

frontend/viewer/src/lib/utils/tabbable.test.ts (3)

1-16: Proper test setup with DOM container management.

The test setup correctly creates a fresh DOM container for each test and cleans up afterward, ensuring test isolation and preventing side effects between tests.


18-55: Comprehensive testing of findFirstTabbable function.

The test cases thoroughly cover all scenarios:

  • Null/undefined input handling
  • No tabbable elements case (correctly expects null return from walker.nextNode())
  • Finding first tabbable element in DOM tree
  • Explicit tabindex handling

The test structure is clear and validates the function's behavior accurately.


57-206: Excellent comprehensive testing of findNextTabbable function.

This test suite covers all critical scenarios for tabbable element navigation:

  • Edge cases: null/undefined inputs, no parent element
  • Error handling: non-tabbable current element
  • Navigation patterns: next element, wrapping, DOM traversal
  • Complex DOM structures: nested containers, mixed element types
  • Special cases: custom tabindex, single element wrapping, deep nesting

The test expectations align perfectly with the function implementation, and the DOM structures used are realistic and representative of actual usage scenarios. This thorough testing ensures the keyboard navigation improvements mentioned in the PR objectives will work reliably.

Comment thread frontend/viewer/src/project/NewEntryButton.svelte
@myieye myieye force-pushed the heavy-rich-text-bug-fixing branch from 0041f96 to fd55835 Compare July 7, 2025 13:40
myieye and others added 4 commits July 8, 2025 09:31

@hahn-kev hahn-kev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me. I merged in develop as an i18n fix had moved the schema to another file

@myieye myieye merged commit ba0b57f into develop Jul 11, 2025
27 checks passed
@myieye myieye deleted the heavy-rich-text-bug-fixing branch July 11, 2025 14:31
@coderabbitai coderabbitai Bot mentioned this pull request Jul 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pressing Enter in rich-text fields causes RangeError Rich-string field bugs/quircks

2 participants